// src/composables/chat/useSocket.ts
import { ref, onUnmounted } from 'vue';
import { io, Socket } from 'socket.io-client';

// Define the shape of your server and client events if possible
// interface ServerToClientEvents {
//   noArg: () => void;
//   basicEmit: (a: number, b: string, c: Buffer) => void;
//   withAck: (d: string, callback: (e: number) => void) => void;
// }

// interface ClientToServerEvents {
//   hello: () => void;
// }

// TODO: Replace with actual backend URL from environment variables or config
const SOCKET_URL = import.meta.env.VITE_SOCKET_URL || 'http://localhost:3000'; // Default URL

let socketInstance: Socket | null = null;
const isConnected = ref(false);
const listeners = new Map<string, (...args: any[]) => void>();

export function useSocket() {

  const connect = () => {
    if (socketInstance && socketInstance.connected) {
      console.log('WebSocket already connected.');
      isConnected.value = true;
      return;
    }

    if (socketInstance) {
      // If instance exists but not connected, try to reconnect
      socketInstance.connect();
      return;
    }

    console.log(`Connecting WebSocket to ${SOCKET_URL}...`);
    socketInstance = io(SOCKET_URL, {
      transports: ['websocket'],
      autoConnect: false, // Connect manually
      reconnection: true,
      reconnectionAttempts: 5,
      reconnectionDelay: 1000,
    });

    socketInstance.on('connect', () => {
      console.log('WebSocket connected:', socketInstance?.id);
      isConnected.value = true;
      // Re-register listeners upon reconnection
      listeners.forEach((callback, event) => {
        if (socketInstance && !socketInstance.hasListeners(event)) {
           socketInstance.on(event, callback);
        }
      });
    });

    socketInstance.on('disconnect', (reason) => {
      console.log('WebSocket disconnected:', reason);
      isConnected.value = false;
      if (reason === 'io server disconnect') {
        // The server has forcefully disconnected the socket
        socketInstance?.connect(); // Optionally attempt reconnection
      }
      // else the socket will automatically try to reconnect
    });

    socketInstance.on('connect_error', (error) => {
      console.error('WebSocket connection error:', error);
      isConnected.value = false;
      // Handle connection errors (e.g., show a notification to the user)
    });

    // Manually connect
    socketInstance.connect();
  };

  const disconnect = () => {
    if (socketInstance) {
      console.log('Disconnecting WebSocket...');
      socketInstance.disconnect();
      // Do not nullify socketInstance here if you want to allow reconnection
    }
  };

  const emit = (event: string, ...args: any[]) => {
    if (socketInstance && isConnected.value) {
      socketInstance.emit(event, ...args);
    } else {
      console.error('Socket not connected. Cannot emit event:', event);
      // Optionally queue the event or notify the user
    }
  };

  const on = (event: string, callback: (...args: any[]) => void) => {
    if (socketInstance) {
       if (!socketInstance.hasListeners(event)) {
         socketInstance.on(event, callback);
       }
       listeners.set(event, callback); // Store listener for re-registration
    } else {
      console.warn('Socket not initialized. Listener will be added upon connection.');
      listeners.set(event, callback); // Store listener anyway
    }
  };

  const off = (event: string) => {
    if (socketInstance) {
      socketInstance.off(event);
    }
    listeners.delete(event); // Remove from stored listeners
  };

  // Ensure disconnection on component unmount is handled by the component using the composable
  // onUnmounted(() => {
  //   // Decide if global socket should disconnect when a component unmounts
  //   // disconnect(); // This might disconnect for other components too
  //   // Instead, clean up specific listeners if needed
  // });

  // Attempt to connect if not already connected
  // Be careful with calling connect() here, might cause multiple connections
  // if (!socketInstance) {
  //   connect();
  // }

  return {
    socket: socketInstance, // Expose the instance directly (use with caution)
    isConnected,
    connect,
    disconnect,
    emit,
    on,
    off,
  };
}